package com.example.emos.wx;

import cn.hutool.core.util.StrUtil;
import com.example.emos.wx.config.SystemConstants_系统常量数据;
import com.example.emos.wx.db.dao.SysConfigDao;
import com.example.emos.wx.db.pojo.SysConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;

import javax.annotation.PostConstruct;
import java.io.File;
import java.lang.reflect.Field;
import java.util.List;

@SpringBootApplication
/*给SpringBoot主类添加@ServletComponentscan注解。xss拦截请求*/
@ServletComponentScan
@Slf4j
@EnableAsync//开启异步线程池
public class EmosWxApiApplication {


    @Autowired
    SysConfigDao sysConfigDao;

    @Autowired
    SystemConstants_系统常量数据 constants;


    @Value("${emos.image-folder}")
    private String imageFolder;


    public static void main(String[] args) {
        SpringApplication.run(EmosWxApiApplication.class, args);
    }



    /**6-7 缓存系统常量数据,放到系统启动时就加载到内存中
     * 原理：从对象中的数据，springboot中的注解，springboot已启动就会直接执行，类似javaee中static
     * 因为这些常量信息跟考勤模块息息相关，所以我们要编写Java代码，在Spring Boot项目启动的时候，就去数据库读取这些常量信息
     * 然后缓存成Java对象，全局都可以使用。 Java对象就是constants，供全局使用
     *
     * 为什么要用到key，value？因为（SystemConstants_系统常量数据）中要存入value的值
     * 而（SystemConstants_系统常量数据）的字段名字是key，则通过数据库中的key与对象封装类里面的key一一对应后
     * 才能把数据库中的value注入封装类
     *
     * 目的：首先是为了在Spring Boot项目启动的时候，就去数据库读取这些常量信息
     * 就注解PostConstruct，交给springboot管理，一启动就运行，将数据库中的ParamKey，ParamValue都取出来，
     * 然后创建一个对象类，将数据插进到对象类中，对象类就可以给全局使用了！
     * 注意驼峰命名
     *
     * 步骤：将数据库中的sysConfigs中获取的 param_value（通过key找到value），存到Systemconstants对象中，
     * 需要映射过去（StrUtil.toCamelCase）
     *
     * 一句话，为了给spring做系统常量数据，把数据库里面的value封装成一个类，而就要找到key，通过key
     *
     * /*简化版可以直接在yml里面注入写死，但是这样就不是从mysql里面读了，以后改的不是在java，而是在mysql*/
    @PostConstruct
    public void init(){
        List<SysConfig> sysConfigs = sysConfigDao.selectAllParam();
        sysConfigs.forEach(one->{
            String key = one.getParamKey();
            String value = one.getParamValue();
            /**数据库中的不是驼峰命名法(数据库里面是param_key，param_value这种形式)，
             * 而映射到constants中的都是驼峰命名法类似attendanceStartTime，需要一一对应后进行映射*/
            key = StrUtil.toCamelCase(key);
            try {
                /**constants.getClass();得到这个对象的class，就是要这个  对象  的  类*/

                /**getDeclaredField()返回一个   反映此Class对象表示的   类或接口   的指定声明字段  的Field对象。
                 *  name参数是一个String ，它指定所需字段的简单名称。如果这个Class对象代表一个数组类型，那么这个方法没有找到数组类型的length字段*/

                /**getDeclaredField根据常量的名字去到封装类里面找到变量，变量的声明是 Field field
                 * 对这个封装类的对象封装上去*/
                /**意思就是去（SystemConstants_系统常量数据）这个类里面找到和key名字一样的字段放在field（就是个字段）*/
                Field field = constants.getClass().getDeclaredField(key);

               //  value传进constants中
                field.set(constants,value);
            }catch (Exception e){
                log.error("执行异常",e);
            }
        });
        /**创建由此抽象路径名命名的目录，包括任何必要但不存在的父目录。*/
        new File(imageFolder).mkdirs();

    }
}